#include "baseobject.h"


//Begin of class Point 
//End of class Point 

//Begin of class Candidate

//获取候选数的状态标记
int Candidate::getValue() const 
{
	return nTag;
}
int Candidate::setValue(int tag)//设置候选数的状态标记
{
	if(tag!=STA_NONE && tag!=STA_NORMAL && tag!=STA_TAG)
	{
		char psztmp[200];
		sprintf(psztmp,"Set bad value [%d] to candidate[%d,%d,%d]!!",tag,STA_NONE,STA_NORMAL,STA_TAG);
                throw StringException(psztmp);
	}
	nTag=tag;
	return nTag;
}

const char* Candidate::toString()
{
	sprintf(pszName,"%d[%d]",nVal,nTag);
	return pszName;
}
//End of class Candidate

//Begin of class Cell
int Cell::registerCellSet(ICellSet *cs)//关联CellSet
{
	for(unsigned int i=0;i<cellsets.size();++i)
	{
		if(cellsets[i]==cs)
		{
			//duplicated!
			return false;
		}
	}
	cellsets.push_back(cs);
	return true;
}

void Cell::connect(ICell *c) //与其他数格建立连接
{
    if(c==this)
        return ;//自己不与自己建立连接
    bool bFound=false;
    for(unsigned int i=0;i<cells.size();++i)
    {
        if(cells[i]==c)
        {
            bFound=true;
            break;
        }
    }
    if(!bFound)
    {
        //先将对方加入自己的连接数格集合
        cells.push_back(c);
        //通知对方连接自己，注释，只建立单向连接
        //c->connect(this);
    }
}

ICells Cell::getConnectedCells() //获取关联的CellSet里的数格集合
{
    return cells;
}


Number Cell::getNumber() const  //获取当前数值
{
	//if(nVal<1||nVal>9) //必要？？？是否有负面影响
	//	nVal=0;
	//是否应该校验一下candidate
	return nVal;
}
Number Cell::setNumber(Number num)//设置数值，不做其他影响
{
	//已经设置数字的情况下，禁止再次设置
	if(nVal!=0 && num!=0)
		return nVal;
	if(num==0)
	{
        for(ICandidates::const_iterator itor=candidates.begin();itor!=candidates.end();++itor)
            (*itor)->setValue(STA_NORMAL);
	}
	else if(UPPER_BOUNDER<num||num<LOWER_BOUNDER) //边界检查
	{
		char psztmp[200];
		sprintf(psztmp,"Try Set Wrong Number[%d] to Cell[%d-%d]!",num,LOWER_BOUNDER,UPPER_BOUNDER);
                throw StringException(psztmp);
	}
	else
	{
        //Set All Candidates to value 'STA_NONE' ---- 将候选数全部清空
        for(ICandidates::const_iterator itor=candidates.begin();itor!=candidates.end();++itor)
            (*itor)->setValue(STA_NONE);
	}
	nVal=num;
	return nVal;
}

int Cell::setCandidate(Number num,int tag)//设置该数个的某个候选数的状态
{
    if(!NumberIsValid(num))
        throw StringException("The setCandidate was called with Invalid Number!");
    return candidates[num-1]->setValue(tag);
}

int Cell::getCandidate(Number num) //试图获取数格某个候选数的状态
{
    if(!NumberIsValid(num))
        throw StringException("The getCandidate was called with Invalid Number!");
    return candidates[num-1]->getValue();
}

ICandidates Cell::getCandidates()//获取候选数列表
{
	return candidates;
}
ICellSets Cell::getCellSets()//获取关联的CellSet
{
	return cellsets;
}

ICellSet *Cell::getCellSet(int nType)//获取指定类型的关联数格集合
{
    for(unsigned int n=0;n<cellsets.size();++n)
    {
        ICellSet * pcs=cellsets[n];
        if(pcs->getType()==nType)
            return cellsets[n];
    }
    char tmp[200];
    sprintf(tmp,"Can't find %d CellSet of %s.",nType,toString());
    throw StringException(tmp);
}

Point Cell::getPoint()  //获取当前坐标值
{
    return pt;
}

const char* Cell::toString()
{
	pszName[0]='\0';
	strcpy(pszName,pt.toString());
	strcat(pszName,"=");
	if(nVal>0)
	{
		char tmp[20];
		sprintf(tmp,"%d",nVal);
		strcat(pszName,tmp);
	}
	return pszName;
}
//End of class Cell

//Begin of class CellSet

//注册此条CellSet关注的数格
bool CellSet::registerCell(ICell *cell)
{
	for(unsigned int i=0;i<cells.size();++i)
	{
		if(cells[i]==cell)
		{
			//duplicated!
			return false;
		}
	}
        //根据类型校验输入cell的坐标
	switch(nType)
	{
    case CellSet_X:
        if(cell->getPoint().getX()!=nId)
		{
			char psztmp[200];
            sprintf(psztmp,"You must register cell with same X coordinate[%d] (cell's X=%d)!",nId,cell->getPoint().getX());
                        throw StringException(psztmp);
		}
		break;
    case CellSet_Y:
        if(cell->getPoint().getY()!=nId)
		{
			char psztmp[200];
            sprintf(psztmp,"You must register cell with same Y coordinate[%d] (cell's Y=%d)!",nId,cell->getPoint().getY());
                        throw StringException(psztmp);
		}
		break;
    case CellSet_Z:
        if(xy2z(cell->getPoint())!=nId)
		{
			char psztmp[200];
            sprintf(psztmp,"You must register cell with same Z coordinate[%d] (cell's Z=%d)!",nId,xy2z(cell->getPoint()));
                        throw StringException(psztmp);
		}
		break;
	}
	cells.push_back(cell);
	return true;
}
//返回关联的数个
ICells CellSet::getCells()
{
	return cells;
}

int CellSet::getType()
{
    return nType;
}

//字符串信息
const char* CellSet::toString()
{
	switch(nType)
	{
    case CellSet_Y:
		sprintf(pszName,"Row:%c",'A'+nId-1);
		break;
    case CellSet_X:
		sprintf(pszName,"Col:%d",nId);
		break;
    case CellSet_Z:
		sprintf(pszName,"Box:%d",nId);
		break;
	default:
		sprintf(pszName,"CellSet:%d/%d",nType,nId);
		break;
	}
	return pszName;
}
//End of class CellSet 

//Begin of class Puzzle
Puzzle::Puzzle() //里面涉及的函数都绝对不应该抛出异常！！！
{
    try{
        memset(pszOrigin,0,sizeof(pszOrigin));
        memset(pszPuzzle,0,sizeof(pszPuzzle));

        //创建规则
        for(unsigned int x=LOWER_BOUNDER;x<=UPPER_BOUNDER;++x)
            col_cellsets.push_back(new CellSet(CellSet_X,x));
        for(unsigned int y=LOWER_BOUNDER;y<=UPPER_BOUNDER;++y)
            row_cellsets.push_back(new CellSet(CellSet_Y,y));
        for(unsigned int z=LOWER_BOUNDER;z<=UPPER_BOUNDER;++z)
            box_cellsets.push_back(new CellSet(CellSet_Z,z));

        //创建数格对象，将数格注册到相关规则上
        for(unsigned int y=LOWER_BOUNDER;y<=UPPER_BOUNDER;++y)
        {
            for(unsigned int x=LOWER_BOUNDER;x<=UPPER_BOUNDER;++x)
            {
                Point p(x,y);
                Cell *cell=new Cell(p);
                cells.push_back(cell);
                col_cellsets[x-1]->registerCell(cell);
                row_cellsets[y-1]->registerCell(cell);
                box_cellsets[CellSet::xy2z(p)-1]->registerCell(cell);
                cell->registerCellSet(col_cellsets[x-1]);
                cell->registerCellSet(row_cellsets[y-1]);
                cell->registerCellSet(box_cellsets[CellSet::xy2z(p)-1]);
            }
        }

        //将数格对象建立连接
        for(unsigned int i=0;i<cells.size();++i)
        {
            ICell* c=cells[i];
            ICellSets css=c->getCellSets();
            for(unsigned int j=0;j<css.size();++j)
            {
                ICells cs=css[j]->getCells();
                for(unsigned int k=0;k<cs.size();++k)
                    c->connect(cs[k]);
            }
        }
    }
    catch(...)
    {
        cerr<<endl<<"Exception in Puzzle's ctor()!"<<endl;
    }
}

//释放资源
Puzzle::~Puzzle()
{
    for(unsigned int i=0;i<cells.size();++i)
        delete cells[i];
    for(unsigned int i=0;i<col_cellsets.size();++i)
        delete col_cellsets[i];
    for(unsigned int i=0;i<row_cellsets.size();++i)
        delete row_cellsets[i];
    for(unsigned int i=0;i<box_cellsets.size();++i)
        delete box_cellsets[i];
}

ICellSets Puzzle::getCellSets(int nType) //根据传入类型，获取数格集合
{
    switch(nType)
    {
    case CellSet_X:
        return col_cellsets;
    case CellSet_Y:
        return row_cellsets;
    case CellSet_Z:
        return box_cellsets;
    default:
        throw StringException("Puzzle::getCellSet(): Unsupported CellSet Type!");
    }
}

void Puzzle::clear()
{
    for(ICells::const_iterator itor=cells.begin();itor!=cells.end();++itor)
    {
        (*itor)->setNumber(0);
    }
}

int Puzzle::loadPuzzle(const char *pszSudoku)
{
	int idx=0;
	const char *p=pszSudoku;
	memset(pszOrigin,0,sizeof(pszOrigin));
    clear();
	while(*p!=0)
	{
		char ch=*p;
		if (ch == '\r' || ch == '\n' || ch == ',' || ch == ';' //suport klsudoku's multiline format
			|| ch== '+' || ch=='-'|| ch=='|' // support klsudoku's matrix format
			)
		{
			++p;
			continue;
		}
		int v=ch-'0';
		if(v<1||v>9)
		{
			v=0;
			ch='0';
		}
        pszOrigin[idx]=ch;
        //Must chainSet,we have to update the candidates of all cells.
        if(NumberIsValid(v)) //When v is 0,skipp it
            chainSetNumber(cells[idx]->getPoint(),v);
        //调试代码
        //cout << endl <<"======== chainSetNumber("<<cells[idx]->getPoint().toString()<< ","<<v<<")=============" << endl << exportPuzzle(FormatFullTable)<<"==================================="<<endl;
		++p;
		++idx;
	}
	return 0;
}

const char* Puzzle::exportPuzzle(int nType)
{
    //前提：cells是有序的，否则应该通过接口来获取CellSet，再输出（似乎就是应该这样才合适，但是cells是Puzzle内部变量，这样也没什么不好）
    switch(nType)
    {
    case FormatFullTableStable:
    case FormatFullTable:
        {
            //必须要在非等宽字体下也保持宽度才合适！
            //使用填表的方式产生导出题，注意表格线在不同的文件字符集下是不一样的，所以要用sizeof来判断一些偏移量
            //目前文件是UTF8字符集的。最好根据环境转换字符集后输出。
            char pszFormatFullTable[]=
                "┏━━━━━┯━━━━━┯━━━━━┳━━━━━┯━━━━━┯━━━━━┳━━━━━┯━━━━━┯━━━━━┓\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┣━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━┫\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┣━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━┫\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┗━━━━━┷━━━━━┷━━━━━┻━━━━━┷━━━━━┷━━━━━┻━━━━━┷━━━━━┷━━━━━┛\r\n";

            strcpy(pszPuzzle,pszFormatFullTable);
            int split_length=strlen("┏━━━━━┯━━━━━┯━━━━━┳━━━━━┯━━━━━┯━━━━━┳━━━━━┯━━━━━┯━━━━━┓\r\n");//utf8里长度不一样
            int line_length=strlen("┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n");//一行的长度
            int step_length=strlen("┃12345");//步长（因为表格符号在UTF8里是用三个字节表示的）
            for(unsigned int y=0;y<row_cellsets.size();++y)
            {
                char * offset_head=pszFormatFullTable+ (y+1)*split_length + y*2*line_length+strlen("┃");//行首偏移量
                ICellSet *cs=row_cellsets[y];
                ICells cells=cs->getCells();
                for(unsigned int x=0;x<cells.size();++x)
                {
                    ICell* cell=cells[x];
                    Number num=cell->getNumber();
                    char sl[11];
                    memset(sl,' ',sizeof(sl));
                    sl[sizeof(sl)-1]='\0';
                    if(NumberIsValid(num))
                    {
                        sl[2]='0'+num;
                    }
                    else
                    {
                        //获取候选数
                        ICandidates cands=cell->getCandidates();
                        int i=0;
                        for(unsigned int n=0;n<cands.size();++n)
                        {
                            ICandidate *cand=cands[n];
                            if(cand->getValue()==STA_NORMAL) //被标记为STA_TAG的也不导出！
                            {
                                if(nType==FormatFullTableStable)
                                    sl[n]='0'+(n+1); //候选数不紧凑，固定位置
                                else
                                    sl[i++]='0'+(n+1);//候选数紧凑，不固定位置
                            }
                        }
                    }
                    //覆盖旧值
                    char * offset=offset_head+x*step_length;
                    //strncpy(offset,sl,5);
                    //strncpy(offset+line_length,sl+5,5);
                    memcpy(offset,sl,5);
                    memcpy(offset+line_length,sl+5,5);
                }
            }
            strcpy(pszPuzzle,pszFormatFullTable);
        }
        break;
    case FormatSimpleTable:
        {
            string tmp=exportPuzzle(FormatNumber81);
            //格式化为无候选数的ASCII表格
            string sb="+---+---+---+\r\n";
            for (int i = 0; i < 9; ++i)
            {
                sb.append("|");
                string strLine = tmp.substr(i * 9, 9);
                for (int j = 0; j < 3; ++j)
                {
                    sb.append(strLine.substr(j*3,3));
                    sb.append("|");
                }
                sb.append("\r\n");
                if ((i + 1) % 3 == 0)
                    sb.append("+---+---+---+\r\n");
            }
            strcpy(pszPuzzle,sb.c_str());
        }
        break;
    case FormatMultiLine:
    default://缺省的81数 //FormatNumber81
        {
            unsigned int i=0;
            unsigned int j=0;
            for(;i<cells.size();++i)
            {
                Number v=(cells[i])->getNumber();
                pszPuzzle[j]=NumberToChar(v);
                j++;
                if(nType==FormatMultiLine && (i+1)%9==0)
                {
                    pszPuzzle[j]='\r';
                    j++;
                    pszPuzzle[j]='\n';
                    j++;
                }
            }
            pszPuzzle[j]='\0';
        }
    }
	return pszPuzzle;
}

ICell * Puzzle::getCell(const Point &p)
{
	return cells[p.getX() + (p.getY()-1)*9 - 1];
}
ICells Puzzle::getCells()//取出全部的数个对象
{
    return cells;
}

Number Puzzle::getNumber(const Point &p)//获取数值
{
	return getCell(p)->getNumber();
}
Number Puzzle::setNumber(const Point &p,Number num)//设置数值，不影响其他数格
{
	ICell *pc=getCell(p);
    return pc->setNumber(num);
}
Number Puzzle::unsetNumber(const Point &p,Number num)//取消数值设置，不影响其他数格
{
	ICell *cell=getCell(p);
	cell->setNumber(0);
	if(num<1 || num>9)
		return 1;
    ICellSets csList=cell->getCellSets();
	for(unsigned int i=0;i<csList.size();++i)
	{
        ICells cs=csList[i]->getCells();
		for(unsigned int j=0;j<cs.size();++j)
		{
			int n=cs[j]->getNumber();
            if(n>0 && !cs[j]->getPoint().isEqual(p) )
                cell->getCandidates()[n-1]->setValue(STA_NONE);
		}
	}
	return 0;
}

//必须实现，自动解题的主要接口
Number Puzzle::chainSetNumber(const Point & p,Number num ) //设置数值，并且触发链式反应
{
    //Number mn=11; (显示某个数的设置过程）

    if(!NumberIsValid(num) && !NumberIsEmpty(num))
    {
        char tmp[200];
        sprintf(tmp,"Call chainSetNumber with Invalid Number[%d]",num);
        throw StringException(tmp);
    }
    ICell *pc=getCell(p);
    pc->setNumber(num);
    if(NumberIsEmpty(num)) //对于设置0恢复的情况，不做下面的操作了（否则不但逻辑错误，而且数组越界崩溃！）
        return 0;
    //if(num==mn) cout << pc->toString() << "setNumber(" << num << ")"<<endl;
    ICells cs=pc->getConnectedCells();
    //if(num==mn) cout << "getConnectedCells has " << cs.size() << "cells!"<<endl;
    for(unsigned int i=0;i<cs.size();++i)
    {
        ICell *c=cs[i];
        if(c->getNumber()>0)
        {
            //if(num==mn) cout << c->getPoint().toString()<< "has been set number,skipped!"<<endl;
            continue;
        }
        //if(num==mn) cout << c->getPoint().toString() << "remove candidate " << num << endl;
        ICandidates cands=c->getCandidates();
        cands[num-1]->setValue(STA_NONE);
    }
    return 0;
}
Number Puzzle::chainUnsetNumber(const Point &p,Number num)//取消设置数值，并且触发链式反应
{
	//链式反应，还应该试图给其他数格恢复该数字为候选数
    ICell *pc=getCell(p);
    pc->setNumber(0);
    ICells cs=pc->getConnectedCells();
    for(unsigned int i=0;i<cs.size();++i)
    {
        ICell *c=cs[i];
        if(c->getNumber()>0) continue;
        if(chkNumber(c->getPoint(),num))
            c->getCandidates()[num-1]->setValue(STA_NORMAL);
    }
	return 0;
}

int Puzzle::setCandidate(const Point &p,Number num,int tag)//设置候选数，不影响其他数格
{
	ICell *cell=getCell(p);
    return cell->setCandidate(num,tag);
}
bool Puzzle::hasCandidate(const Point &p,Number num)//检查某数格是否设置了某候选数（应用于解题算法，只有NORMAL的才视作可填写）
{
	ICell *cell=getCell(p);
    return (cell->getCandidates()[num-1]->getValue()==STA_NORMAL);

}

bool Puzzle::chkNumber(const Point &p,Number num)//检查某数格是否可以填某数（在可见数格里不冲突）
{
    ICell *pc=getCell(p);
    ICells cs=pc->getConnectedCells();
    for(unsigned int i=0;i<cs.size();++i)
    {
        ICell *c=cs[i];
        if(c->getNumber()==num)
            return false;
    }
    return true;
}

int Puzzle::getStatus()
{
    //检查当前数格状态，得出合法与否的标记：未完成但有效PuzzleIsPlaying，完成且有效PuzzleIsOver，存在错误PuzzleHasError
    try
    {
    vector<int> cstype;
    cstype.push_back(CellSet_X);
    cstype.push_back(CellSet_Y);
    cstype.push_back(CellSet_Z);

    bool hasUnsetCell=false;

    for(unsigned int i=0;i<cstype.size();++i)
    {
        ICellSets css=this->getCellSets(cstype[i]);
        for(unsigned int j=0;j<css.size();++j)
        {
            ICellSet *cs=css[j];
            //对行列宫校验是否符合规则（不重复）
            vector<int> cnt(UPPER_BOUNDER);
            ICells cells=cs->getCells();
            for(unsigned int k=0;k<cells.size();++k)
            {
                ICell *cell=cells[k];
                Number n=cell->getNumber();
                if(NumberIsValid(n))
                {
                    cnt[n-1]++;
                }
                else if(NumberIsEmpty(n))
                {
                    hasUnsetCell=true;
                    continue;
                }
                else
                    return PuzzleHasError;
            }
            for(unsigned int k=0;k<cnt.size();++k)
                if(cnt[k]>1)
                    return PuzzleHasError;
        }
    }

    if(hasUnsetCell)
        return PuzzleIsPlaying;
    }
    catch(...)
    {
        throw StringException("getStatus can't work!");
    }

    return PuzzleIsOver;
}

//End of class Puzzle


//Begin of class Solver

int Solver::doSolve(IPuzzle *pz,Operations &opsret)  //开始解题 ;
{
    int maxloop=1000;
    int loop=0;
    opsret.clear();
    Operations tmp;
    while(!doStep(pz,tmp,3) )
    {
        //记录解题步骤
        opsret.insert(opsret.end(),tmp.begin(),tmp.end());
        //for(unsigned int i=0;i<tmp.size();++i) opsret.push_back(tmp[i]);
        if(++loop > maxloop)
        {
            cerr<<"Solver::doSolver loop over " << maxloop << endl;
            break;
        }
    };
    return pz->getStatus();
}

//这不是一个效率优先的方法，返回0表示成功
int Solver::doStep(IPuzzle *pz,Operations &opsret,int nStep) //处理若干步骤
{
    opsret.clear();
    //cout << "doStep() was called!"<<endl;
    int n=0;
    while(true)
    {
        Operations ops=getTips(pz,nStep);
        if(ops.size()<1)
        {
            if(opsret.size()>0) //说明之前的nStep次操作成功处理
                return 0;
            return 1;//说明一次操作都未能发现和处理
        }
        for(unsigned int i=0;i<ops.size();++i)
        {
            Operation op=ops[i];
            Points pts=op.getPoints();
            Numbers nums=op.getNumbers();
            if(pts.size()<1 || nums.size()<1)
                return 2;
            opsret.push_back(op);
            //循环处理
            //cout << "doStep():" << op.toString() << endl;
            for(unsigned int pi=0;pi<pts.size();++pi)
            {
                Point pt=pts[pi];
                for(unsigned int ni=0;ni<nums.size();++ni)
                {
                    Number num=nums[ni];
                    switch(op.getType())
                    {
                    case OperationSetNumber:
                        pz->chainSetNumber(pt,num);
                        break;
                    case OperationUnsetNumber:
                        pz->chainUnsetNumber(pt,num);
                        break;
                    case OperationTagCandidateDelete:
                        pz->setCandidate(pt,num,STA_TAG);
                        break;
                    case OperationTagCandidateNone:
                        pz->setCandidate(pt,num,STA_NONE);
                        break;
                    case OperationTagCandidateNormal:
                        pz->setCandidate(pt,num,STA_NORMAL);
                        break;
                    default:
                        throw StringException("Invalid Operation Type!");
                    }
                    if(++n >= nStep) //如果执行操作达到step步，则结束本次处理
                    {
                        //cout <<"over "<< nStep << "(" << n <<") steps!"<< opsret.size()<<endl ;
                        return 0;
                    }
                }
            }
        }
    }
    //cout <<"over "<< nStep << "(" << n <<") steps!"<< opsret.size()<<endl ;
    return 0;
}

//对getActioncs接口的实现需要稍微考虑运行速度
Operations Solver::getTips(IPuzzle *pz,int nStep)//获取提示
{
	for(unsigned int i=0;i<helpers.size();++i)
	{
		IHelper *hpr=helpers[i];
        Operations ops=hpr->getActions(pz,nStep); //nStep只建议最多提示数，未必能有那么多
		if(ops.size()>0)
			return ops;
	}
    return Operations();
}

int Solver::registerHelper(IHelper *helper)  //注册解题接口，顺序相关
{
	helpers.push_back(helper);
	return helpers.size();
}

//End of class Solver


